package com.nanbei.a05;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.stereotype.Component;

/**
 * @ClassDescription:   ComponentScan bean工厂后置处理器
 * @JdkVersion: 1.8
 * @Author: libs
 * @Created: 2024/11/13 16:26
 */
public class ComponentScanPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        try{
            ComponentScan annotation = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
            if (annotation != null){
                // 如果路径不为空，则遍历路径
                for (String s : annotation.basePackages()) {
                    // com.nanbei.a05.component  ===> classpath*:com/nanbei/a05/component/**/*.class
                    String path = "classpath*:" + s.replace(".", "/") + "/**/*.class";
                    CachingMetadataReaderFactory readerFactory = new CachingMetadataReaderFactory();
                    AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
                    // 获取路径下的类
                    Resource[] resources = new PathMatchingResourcePatternResolver().getResources(path);
                    for (Resource resource : resources) {
                        MetadataReader metadataReader = readerFactory.getMetadataReader(resource);
                        ClassMetadata classMetadata = metadataReader.getClassMetadata();
                        System.out.println( "类名为：" + classMetadata.getClassName());
                        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
                        System.out.println( "类是否加了 @Component 注解 ："+ annotationMetadata.hasAnnotation(Component.class.getName()));
                        System.out.println( "类是否加了 @Component 衍生注解 ："+ annotationMetadata.hasMetaAnnotation(Component.class.getName()));

                        if (annotationMetadata.hasAnnotation(Component.class.getName()) ||
                                annotationMetadata.hasMetaAnnotation(Component.class.getName())){
                            // 创建 beanDefinition
                            AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
                                    .genericBeanDefinition(classMetadata.getClassName())
                                    .getBeanDefinition();

                            // 为给定的 bean 定义生成 bean 名称
                            if (configurableListableBeanFactory instanceof DefaultListableBeanFactory ){
                                // 获取bean 工厂
                                DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;
                                // 获取bean 名称
                                String beanName = generator.generateBeanName(beanDefinition, beanFactory);
                                // 注册bean定义
                                beanFactory.registerBeanDefinition(beanName,beanDefinition);
                            }
                        }
                    }
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
